#ifndef RSIM_CDATA_H
#define RSIM_CDATA_H

/* -------------------------------------------------------------------------- *
 * File: CData.h                                                              *
 * Authors: Kishor Bhalerao                                                   *
 * Email : kishor8dm@gmail.com                                                *
 * Contributors:                                                              *
 * Email:                                                                     *
 * copyright (c) 2010 Authors.                                                *
 *                                                                            *
 * This program is free software: you can redistribute it and/or modify it    *
 * under the terms of the GNU General Public License as published by the Free *
 * Software Foundation, either version 3 of the License, or any later version.*
 *                                                                            *
 * This program is distributed in the hope that it will be useful, but        *
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License   *
 * for more details. (http://www.gnu.org/licenses/)                           *
 * -------------------------------------------------------------------------- */
#include <iostream>
using namespace std;

namespace RSIM{
        
/**
This is the base container classes for Matrix and Vector. The data is stored in 
a contiguous block of length equal to the number of elements in the matrix/vector.
The indexing is 0 based. 
*/

template <class T>
class cData{
        protected:
                /** This stores the actual data */
                T *data_;
                
                /** Total elements in the contiguous block */
                int nele_;	
                
                /** Null pointer */
                cData();
                
                /** @param len Length of contiguous block */
                explicit cData(const int& len);
                
                /** Deep copy */
                cData(const cData& Ar);
                
                /** Deep copy */
                cData(const cData& Ar, const int& len);
                
                /** Initialize from a given pointer. Caution. No checks to 
                ensure the validity of *ptr or len */
                cData(const int& len, const T *ptr);
                
                /** Allocate space, set each element to val */
                cData(const int& len, const T& val);
                
                /** Deep copy */
                void operator=(const cData& Ar); // Excess clear() call.
                
                /** Clear memory. Results in NULL pointer */
                void clear_();
                
                /** @param len Clear memory if already alloted. Allocate contiguous block of memory */
                void setLength(const int& len); // Excess clear call.
                
                /** Set all elements to zero */
                void Zeros_();
                
                /** Clear memory */
                ~cData();
                
        public:
                /** get length of the contiguous block */
                int getLength() const;		
                
                /** @return Returns a const pointer to the data of the function */
                const T* Ptr() const;
                
                /** @return Writable (w) pointer to the data. */
                T* wPtr();				
        
}; // class cData

///////////////////////////////////////////////////////////////
template <class T>
inline int cData<T>::getLength() const {return nele_;}

///////////////////////////////////////////////////////////////
template <class T>
inline const T* cData<T>::Ptr() const {return data_;}

///////////////////////////////////////////////////////////////
template <class T>
inline T* cData<T>::wPtr(){return data_;}

///////////////////////////////////////////////////////////////
template <class T>
cData<T>::cData(const cData& Ar):data_(NULL),nele_(Ar.getLength()){
        if(this->nele_){
                data_ = new T[nele_];
                const T *ptr = Ar.Ptr();
                for(int i=0;i<nele_;++i)
                        data_[i] = ptr[i];
        }
}

///////////////////////////////////////////////////////////////
template <class T>
inline cData<T>::cData():data_(NULL),nele_(0){}

///////////////////////////////////////////////////////////////
template <class T>
inline cData<T>::cData(const int& len):data_(new T [len]),nele_(len){
}

///////////////////////////////////////////////////////////////
template <class T>
inline void cData<T>::clear_(){	
        delete [] data_; 
        data_ = NULL; 
        nele_ = 0;
}

///////////////////////////////////////////////////////////////
template <class T>
void cData<T>::Zeros_(){
        if(nele_ && data_){
                for(int i=0;i<nele_;i++)
                        data_[i]=0.0;
        }
}

///////////////////////////////////////////////////////////////
template <class T>
cData<T>::~cData(){	
        delete[]data_;
}

///////////////////////////////////////////////////////////////
template <class T>
cData<T>::cData(const cData& Ar, const int& len):data_(new T[len]),nele_(len){
        const T *ptr = Ar.Ptr();
        for(int i=0;i<len;++i)
                data_[i] = ptr[i];
}

///////////////////////////////////////////////////////////////
template <class T>
cData<T>::cData(const int& len, const T *ptr):data_(new T[len]),nele_(len){
        for(int i=0;i<len;++i)
                data_[i] = ptr[i];
}

///////////////////////////////////////////////////////////////
template <class T>
cData<T>::cData(const int& len, const T& val):data_(new T[len]),nele_(len){
        for(int i=0;i<len;++i)
                data_[i] = val;
}

///////////////////////////////////////////////////////////////
template <class T>
void cData<T>::operator=(const cData& Ar){
        this->clear_();
        this->nele_ = Ar.getLength();
        if(this->nele_){
                data_ = new T[nele_];
                const T *ptr = Ar.Ptr();
                for(int i=0;i<nele_;++i)
                        data_[i] = ptr[i];
        }
}

///////////////////////////////////////////////////////////////
template <class T>
void cData<T>::setLength(const int& len){
        if(len){
                this->clear_();
                nele_ = len;
                data_ = new T [len];
        }
}

///////////////////////////////////////////////////////////////

} // namespace RSIM

#endif